From 2ca1179da8e17f151e515960b9814c7b77c4230e Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 3 Aug 2005 12:51:35 +0000 Subject: [PATCH] Virtual device drivers use new bind_evtchn_to_irqhandler() call instead of directly interfacing with Linux IRQ subsystem. This allows them to be used in situations where the IRQ subsystem is not paravirtualised. Signed-off-by: Keir Fraser --- .../arch/xen/i386/kernel/smpboot.c | 6 +- .../arch/xen/i386/kernel/time.c | 2 + linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c | 81 ++++++++++++------- linux-2.6-xen-sparse/arch/xen/kernel/reboot.c | 1 + .../drivers/xen/blkback/blkback.c | 1 - .../drivers/xen/blkback/common.h | 2 +- .../drivers/xen/blkback/interface.c | 7 +- .../drivers/xen/blkfront/blkfront.c | 14 ++-- .../drivers/xen/netback/common.h | 1 + .../drivers/xen/netback/netback.c | 1 - .../asm-xen/asm-i386/mach-xen/irq_vectors.h | 14 ---- .../asm-xen/asm-x86_64/mach-xen/irq_vectors.h | 14 ---- linux-2.6-xen-sparse/include/asm-xen/evtchn.h | 29 +++++++ 13 files changed, 100 insertions(+), 73 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c index 87d0d07343..1b3d1c7e6f 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -62,6 +62,8 @@ #include #include +#include + /* Set if we find a B stepping CPU */ static int __initdata smp_b_stepping; @@ -1534,13 +1536,13 @@ void smp_intr_init(void) int cpu = smp_processor_id(); per_cpu(resched_irq, cpu) = - bind_ipi_on_cpu_to_irq(RESCHEDULE_VECTOR); + bind_ipi_to_irq(RESCHEDULE_VECTOR); sprintf(resched_name[cpu], "resched%d", cpu); BUG_ON(request_irq(per_cpu(resched_irq, cpu), smp_reschedule_interrupt, SA_INTERRUPT, resched_name[cpu], NULL)); per_cpu(callfunc_irq, cpu) = - bind_ipi_on_cpu_to_irq(CALL_FUNCTION_VECTOR); + bind_ipi_to_irq(CALL_FUNCTION_VECTOR); sprintf(callfunc_name[cpu], "callfunc%d", cpu); BUG_ON(request_irq(per_cpu(callfunc_irq, cpu), smp_call_function_interrupt, diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c index f64d6d1d26..fe732b2809 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c @@ -70,6 +70,8 @@ #include "io_ports.h" +#include + extern spinlock_t i8259A_lock; int pit_latch_buggy; /* extern */ diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c index 2a15fd5965..005caf3a21 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c @@ -229,12 +229,13 @@ void unbind_virq_from_irq(int virq) if ( HYPERVISOR_event_channel_op(&op) != 0 ) panic("Failed to unbind virtual IRQ %d\n", virq); - /* This is a slight hack. Interdomain ports can be allocated - directly by userspace, and at that point they get bound by - Xen to vcpu 0. We therefore need to make sure that if we - get an event on an event channel we don't know about vcpu 0 - handles it. Binding channels to vcpu 0 when closing them - achieves this. */ + /* + * This is a slight hack. Interdomain ports can be allocated directly + * by userspace, and at that point they get bound by Xen to vcpu 0. We + * therefore need to make sure that if we get an event on an event + * channel we don't know about vcpu 0 handles it. Binding channels to + * vcpu 0 when closing them achieves this. + */ bind_evtchn_to_cpu(evtchn, 0); evtchn_to_irq[evtchn] = -1; irq_to_evtchn[irq] = -1; @@ -244,7 +245,7 @@ void unbind_virq_from_irq(int virq) spin_unlock(&irq_mapping_update_lock); } -int bind_ipi_on_cpu_to_irq(int ipi) +int bind_ipi_to_irq(int ipi) { evtchn_op_t op; int evtchn, irq; @@ -306,7 +307,7 @@ void unbind_ipi_from_irq(int ipi) spin_unlock(&irq_mapping_update_lock); } -int bind_evtchn_to_irq(int evtchn) +int bind_evtchn_to_irq(unsigned int evtchn) { int irq; @@ -326,7 +327,7 @@ int bind_evtchn_to_irq(int evtchn) return irq; } -void unbind_evtchn_from_irq(int evtchn) +void unbind_evtchn_from_irq(unsigned int evtchn) { int irq = evtchn_to_irq[evtchn]; @@ -341,6 +342,33 @@ void unbind_evtchn_from_irq(int evtchn) spin_unlock(&irq_mapping_update_lock); } +int bind_evtchn_to_irqhandler( + unsigned int evtchn, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id) +{ + unsigned int irq; + int retval; + + BUG_ON((irqflags & ~SA_SAMPLE_RANDOM) != 0); + + irq = bind_evtchn_to_irq(evtchn); + retval = request_irq(irq, handler, irqflags, devname, dev_id); + if ( retval != 0 ) + unbind_evtchn_from_irq(evtchn); + + return retval; +} + +void unbind_evtchn_from_irqhandler(unsigned int evtchn, void *dev_id) +{ + unsigned int irq = evtchn_to_irq[evtchn]; + free_irq(irq, dev_id); + unbind_evtchn_from_irq(evtchn); +} + static void do_nothing_function(void *ign) { } @@ -358,34 +386,33 @@ static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu) return; } - /* Tell Xen to send future instances of this interrupt to the - other vcpu */ + /* Tell Xen to send future instances of this interrupt to other vcpu. */ op.cmd = EVTCHNOP_bind_vcpu; op.u.bind_vcpu.port = evtchn; op.u.bind_vcpu.vcpu = tcpu; - /* If this fails, it usually just indicates that we're dealing - with a virq or IPI channel, which don't actually need to be - rebound. Ignore it, but don't do the xenlinux-level rebind - in that case. */ + /* + * If this fails, it usually just indicates that we're dealing with a virq + * or IPI channel, which don't actually need to be rebound. Ignore it, + * but don't do the xenlinux-level rebind in that case. + */ if (HYPERVISOR_event_channel_op(&op) >= 0) bind_evtchn_to_cpu(evtchn, tcpu); spin_unlock(&irq_mapping_update_lock); - /* Now send the new target processor a NOP IPI. When this - returns, it will check for any pending interrupts, and so - service any that got delivered to the wrong processor by - mistake. */ - /* XXX: The only time this is called with interrupts disabled is - from the hotplug/hotunplug path. In that case, all cpus are - stopped with interrupts disabled, and the missed interrupts - will be picked up when they start again. This is kind of a - hack. - */ - if (!irqs_disabled()) { + /* + * Now send the new target processor a NOP IPI. When this returns, it + * will check for any pending interrupts, and so service any that got + * delivered to the wrong processor by mistake. + * + * XXX: The only time this is called with interrupts disabled is from the + * hotplug/hotunplug path. In that case, all cpus are stopped with + * interrupts disabled, and the missed interrupts will be picked up when + * they start again. This is kind of a hack. + */ + if (!irqs_disabled()) smp_call_function(do_nothing_function, NULL, 0, 0); - } } diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c index 5c99babb26..e56e1edcee 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @@ -12,6 +12,7 @@ static int errno; #include #include #include +#include #include #include #include diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c b/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c index 1fbead78c4..50c609fafb 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c @@ -12,7 +12,6 @@ */ #include "common.h" -#include #ifdef CONFIG_XEN_BLKDEV_GRANT #include #endif diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/common.h b/linux-2.6-xen-sparse/drivers/xen/blkback/common.h index f3331a06a9..bc36983ce7 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/common.h +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/common.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,6 @@ typedef struct blkif_st { /* Physical parameters of the comms window. */ unsigned long shmem_frame; unsigned int evtchn; - int irq; /* Comms information. */ blkif_back_ring_t blk_ring; /* VBDs attached to this interface. */ diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c index aaa976c557..accfd77963 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c @@ -38,7 +38,7 @@ static void __blkif_disconnect_complete(void *arg) * may be outstanding requests at the disc whose asynchronous responses * must still be notified to the remote driver. */ - unbind_evtchn_from_irq(blkif->evtchn); + unbind_evtchn_from_irqhandler(blkif->evtchn, blkif); #ifdef CONFIG_XEN_BLKDEV_GRANT { @@ -247,12 +247,12 @@ void blkif_connect(blkif_be_connect_t *connect) BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE); blkif->evtchn = evtchn; - blkif->irq = bind_evtchn_to_irq(evtchn); blkif->shmem_frame = shmem_frame; blkif->status = CONNECTED; blkif_get(blkif); - request_irq(blkif->irq, blkif_be_int, 0, "blkif-backend", blkif); + bind_evtchn_to_irqhandler( + blkif->evtchn, blkif_be_int, 0, "blkif-backend", blkif); connect->status = BLKIF_BE_STATUS_OKAY; } @@ -277,7 +277,6 @@ int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id) blkif->status = DISCONNECTING; blkif->disconnect_rspid = rsp_id; wmb(); /* Let other CPUs see the status change. */ - free_irq(blkif->irq, blkif); blkif_deschedule(blkif); blkif_put(blkif); return 0; /* Caller should not send response message. */ diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c index 04c0f0fdbf..cc57bb4915 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c @@ -78,7 +78,6 @@ static void vbd_update(void){}; static int blkif_handle = 0; static unsigned int blkif_state = BLKIF_STATE_CLOSED; static unsigned int blkif_evtchn = 0; -static unsigned int blkif_irq = 0; static int blkif_control_rsp_valid; static blkif_response_t blkif_control_rsp; @@ -1159,10 +1158,7 @@ static void blkif_free(void) free_page((unsigned long)blk_ring.sring); blk_ring.sring = NULL; } - free_irq(blkif_irq, NULL); - blkif_irq = 0; - - unbind_evtchn_from_irq(blkif_evtchn); + unbind_evtchn_from_irqhandler(blkif_evtchn, NULL); blkif_evtchn = 0; } @@ -1266,12 +1262,12 @@ static void blkif_connect(blkif_fe_interface_status_t *status) int err = 0; blkif_evtchn = status->evtchn; - blkif_irq = bind_evtchn_to_irq(blkif_evtchn); - err = request_irq(blkif_irq, blkif_int, SA_SAMPLE_RANDOM, "blkif", NULL); - if ( err ) + err = bind_evtchn_to_irqhandler( + blkif_evtchn, blkif_int, SA_SAMPLE_RANDOM, "blkif", NULL); + if ( err != 0 ) { - WPRINTK("request_irq failed (err=%d)\n", err); + WPRINTK("bind_evtchn_to_irqhandler failed (err=%d)\n", err); return; } diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/common.h b/linux-2.6-xen-sparse/drivers/xen/netback/common.h index aa780027e2..8a4eaadc28 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h +++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index b85d75ac13..edc6c67d1f 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -12,7 +12,6 @@ #include "common.h" #include -#include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) #include diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h index 59be3829ee..f4cde5f102 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h @@ -124,18 +124,4 @@ #define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE) #define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE) -#ifndef __ASSEMBLY__ -/* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */ -extern int bind_virq_to_irq(int virq); -extern void unbind_virq_from_irq(int virq); -extern int bind_ipi_to_irq(int ipi); -extern int bind_ipi_on_cpu_to_irq(int ipi); -extern void unbind_ipi_from_irq(int ipi); -extern int bind_evtchn_to_irq(int evtchn); -extern void unbind_evtchn_from_irq(int evtchn); - -extern void irq_suspend(void); -extern void irq_resume(void); -#endif /* __ASSEMBLY__ */ - #endif /* _ASM_IRQ_VECTORS_H */ diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h index 4d3023498c..690560c823 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h @@ -122,18 +122,4 @@ #define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE) #define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE) -#ifndef __ASSEMBLY__ -/* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */ -extern int bind_virq_to_irq(int virq); -extern void unbind_virq_from_irq(int virq); -extern int bind_ipi_to_irq(int ipi); -extern int bind_ipi_on_cpu_to_irq(int ipi); -extern void unbind_ipi_from_irq(int ipi); -extern int bind_evtchn_to_irq(int evtchn); -extern void unbind_evtchn_from_irq(int evtchn); - -extern void irq_suspend(void); -extern void irq_resume(void); -#endif /* __ASSEMBLY__ */ - #endif /* _ASM_IRQ_VECTORS_H */ diff --git a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h index a1801c1981..e38e6822c8 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/evtchn.h +++ b/linux-2.6-xen-sparse/include/asm-xen/evtchn.h @@ -32,6 +32,7 @@ #define __ASM_EVTCHN_H__ #include +#include #include #include #include @@ -42,6 +43,34 @@ * LOW-LEVEL DEFINITIONS */ +/* Dynamically bind a VIRQ source to Linux IRQ space. */ +extern int bind_virq_to_irq(int virq); +extern void unbind_virq_from_irq(int virq); + +/* Dynamically bind an IPI source to Linux IRQ space. */ +extern int bind_ipi_to_irq(int ipi); +extern void unbind_ipi_from_irq(int ipi); + +/* Dynamically bind an event-channel port to Linux IRQ space. */ +extern int bind_evtchn_to_irq(unsigned int evtchn); +extern void unbind_evtchn_from_irq(unsigned int evtchn); + +/* + * Dynamically bind an event-channel port to an IRQ-like callback handler. + * On some platforms this may not be implemented via the Linux IRQ subsystem. + * You *cannot* trust the irq argument passed to the callback handler. + */ +extern int bind_evtchn_to_irqhandler( + unsigned int evtchn, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id); +extern void unbind_evtchn_from_irqhandler(unsigned int evtchn, void *dev_id); + +extern void irq_suspend(void); +extern void irq_resume(void); + /* Entry point for notifications into Linux subsystems. */ asmlinkage void evtchn_do_upcall(struct pt_regs *regs); -- 2.30.2